#include "mod_gprs.h"

#include "usart.h"
#include "platform.h"
#include "port.h"

#include <stdlib.h>
#include <string.h>

struct T_NetGprs {
    uint8_t serveip[4];  //远程服务器IP地址
    uint32_t serveport;  //远程服务器端口号
    int reLinkCnt; //记录上电后网络重连次数
    uint8_t linkstate;
};

enum {GPRS_SUCCESS = 0, GPRS_ERR = -1};

#define GPRS_SEND_BUF_CNT 3
#define GPRS_SEND_BUF_LEN_MAX 512
#define GPRS_RECV_BUF_LEN_MAX 1500
#define GPRS_RECV_ACK_BUF_LEN 100
#define GPRS_RECV_DATA_LEN 2048

static struct T_NetGprs g_gprs = {0};
static char_t g_recv_ack_buf[GPRS_RECV_ACK_BUF_LEN] = {0};
static int32_t g_recv_ack_buf_len = 0;


static void GprsRecv_SetAckData(const char *buf, int len) {
    if (g_recv_ack_buf_len + len < GPRS_RECV_ACK_BUF_LEN){
        memcpy(&g_recv_ack_buf[g_recv_ack_buf_len], buf, len);
        g_recv_ack_buf_len += len;
    }
}

static int GprsRecv_GetAckData(char *buf, int len) {
    int32_t read_len = (len < g_recv_ack_buf_len)? len:g_recv_ack_buf_len;
    memcpy(buf, g_recv_ack_buf, read_len);
    return read_len;
}

static void GprsRecv_ClearAckData() {
    memset(g_recv_ack_buf, 0, sizeof(g_recv_ack_buf));
    g_recv_ack_buf_len = 0;
}

//gprs 接收解析
struct T_GprsRecv {
    uint32_t len;
    char buf[GPRS_RECV_BUF_LEN_MAX];
};

static xQueueHandle gprs_recv_queue = NULL;

int32_t gprs_set_msg(char_t *buf, uint32_t len){
    for(uint32_t i=0;i<len;i++){
          xQueueSend(gprs_recv_queue, &buf[i], portTICK_PERIOD_MS);
    }
    return 0;
}

static void GprsRecv_Push(struct T_GprsRecv *gr, uint8_t val) {
    if (gr->len >= GPRS_RECV_BUF_LEN_MAX) {
        printf("GprsRecv_Push len >= GPRS_RECV_BUF_LEN_MAX\r\n");
        return;
    }
    gr->buf[gr->len++] = (char)val;
}

static void GprsRecv_Clear(struct T_GprsRecv *gr) {
    memset(gr->buf, 0, GPRS_RECV_BUF_LEN_MAX);
    gr->len = 0;
}

static int32_t GprsRecv_IsValidAck(const struct T_GprsRecv *gr) {
    return (gr->len > 2);
}

static uint32_t GetLen(const char *p, uint32_t len) {
    char buf[10] = {0};
    for (uint8_t i = 5, j = 0; i < len; i++, j++) {
        buf[j] = *(p + i);
        if(*(p + i + 1) == ':') {
            break;
        }
    }
    return (uint32_t)atoi((const char *)buf);
}

static uint32_t GetPos(const char *buf, uint32_t len) {
    uint32_t pos = 0;
    for(uint32_t i = 0; i < len ; i++) {
        if(*(buf + i) == ':') {
            pos = i + 1;
            break;
        }
    }
    return pos;
}

struct T_IpdInfo {
    char *pos;
    uint32_t len;
};

static struct T_IpdInfo GetIPDData(struct T_GprsRecv *gr) {
    struct T_IpdInfo info = {0};

    //如果接收的是+IPD开始的表示是收到的数据
    if (strstr(gr->buf, "+IPD") != NULL && strstr(gr->buf, ",") != NULL && strstr(gr->buf, ":") != NULL) {
        uint32_t L = GetLen(gr->buf, gr->len);
        uint32_t pos = GetPos(gr->buf, gr->len);

        //说明接收到了一个完整的ipd包
        if (gr->len - pos == L) {
            info.pos = &gr->buf[pos];
            info.len = L;
        }
    }

    return info;
}

static struct T_GprsRecv g_gprsRcv = {0};

//中断调用函数
void GprsRecv_Parse(uint8_t val) {
    GprsRecv_Push(&g_gprsRcv, val);
    struct T_IpdInfo ret = GetIPDData(&g_gprsRcv);
    if(ret.len != 0) { //说明有一条完整的IPD数据
        //发送或存储数据
        gprs_set_msg(ret.pos, ret.len);
        
        GprsRecv_Clear(&g_gprsRcv);
    } else { //说明没有IPD数据
        if('\n' == val) {
            if (GprsRecv_IsValidAck(&g_gprsRcv)) {
                GprsRecv_SetAckData(g_gprsRcv.buf, (int)g_gprsRcv.len);
            }
            GprsRecv_Clear(&g_gprsRcv);
        }
    }
}

static void NetGprs_Reset() {
    gprs_power_off();
    os_msleep(2000);
    gprs_power_on() ;
}

static int NetGprs_GprsWrite(const char *cmd, uint32_t len) {
    //printf("-->len:%d %s\r\n",len,cmd);
    usart3_send((uint8_t *)cmd, len);
    return 0;
}

int32_t FindGprsMsg(const char *msg) {
    char buf[100] = {0};
    int ret = GprsRecv_GetAckData(buf, sizeof(buf));
    if (ret) {
        return (strstr(buf, msg) == NULL) ? 0 : 1;
    }
    return 0;
}

static int NetGprs_GetAck(const char *ack, int msec) {
    int recCnt = msec / 200;
    uint32_t cnt = 0;
    while(recCnt) {
        os_msleep(200);
        
        cnt++;
        
        recCnt--;

        int32_t i = FindGprsMsg((char *)"ERROR\r\n");
        if(i) { //如果error在里面
            GprsRecv_ClearAckData();//清掉接收区
            return GPRS_ERR;
        }
        i = FindGprsMsg((char *)ack);
        if(i) {
            GprsRecv_ClearAckData();
            return GPRS_SUCCESS;

        }
    }
    GprsRecv_ClearAckData();
    return GPRS_ERR;
}

static int NetGprs_SendCmd(const char *cmd, const char *ack, int msec, int cnt) {
    //printf("SendCmd %s",cmd);
    for (uint8_t i = 0; i < cnt; i++) {
        GprsRecv_ClearAckData();
        NetGprs_GprsWrite(cmd, strlen(cmd));
        if (msec == 0) {
            return GPRS_SUCCESS;
        }
        if (NetGprs_GetAck(ack, msec) == GPRS_SUCCESS) {
            return GPRS_SUCCESS;
        }
    }
    return GPRS_ERR;
}

static int32_t NetGprs_CheckGprsLink(void) {
    if (NetGprs_SendCmd("AT+CIPSTATUS\n", "CONNECT OK\r\n", 1000, 2) == GPRS_SUCCESS) {
        printf("NetGprs_CheckGprsLink link ok\r\n");
        return 1;
    }
    printf("NetGprs_CheckGprsLink unlink\r\n");
    return 0;
}

static int NetGprs_SendATCIPSTART(const struct T_NetGprs *ng) {
    char buf[100] = {0};
    sprintf(buf, "AT+CIPSTART=\"TCP\",\"%d.%d.%d.%d\",\"%d\"\n", ng->serveip[0], ng->serveip[1], ng->serveip[2], ng->serveip[3], (int)ng->serveport);

    NetGprs_GprsWrite(buf, strlen(buf));
    for(uint32_t i = 0; i < 75; i++) {
        os_msleep(1000);//延时1秒钟
        if (FindGprsMsg((char *)"CONNECT OK\r\n")) {
            GprsRecv_ClearAckData();//清掉接收区
            return 1;
        }
        if(FindGprsMsg((char *)"CONNECT FAIL\r\n")) {
            GprsRecv_ClearAckData();
            return 0;
        }
    }
    GprsRecv_ClearAckData(); //清掉接收区
    return 0;
}

void NetGprs_SetGPRSLink(struct T_NetGprs *ng, int32_t state) {
    g_gprs.linkstate = state;
}
/*lint -e{801} */
static int NetGprs_Connect(struct T_NetGprs *ng) {
    printf("gprs connect......reLinkCnt:%d\r\n", ng->reLinkCnt);
    os_msleep(3000);//需要13秒整个模块才准备好

    NetGprs_SendCmd("ATE0\n", "", 200, 1); //关闭回显 发送 ATE0\n

    if (NetGprs_SendCmd("AT+CPIN?\n", "+CPIN: READY\r\n", 2000, 5) != GPRS_SUCCESS) { //发送 AT+CPIN?\n 应答 +CPIN: READY
        printf("NetGprs_SendCmd AT+CPIN? err\r\n");
        goto OVER;
    }

    NetGprs_SendCmd("AT+CSQ\n", "", 1000, 1);

    if (NetGprs_SendCmd("AT+CGATT?\n", "+CGATT: 1\r\n", 2000, 15) != GPRS_SUCCESS) { //查询当前gprs附着状态  发送 AT+CGATT?\n 应答 +CGATT: 1
        printf("NetGprs_SendCmd AT+CGATT? err\r\n");
        goto OVER;
    }

    if (NetGprs_SendCmd("AT+CIPSHUT\n", "SHUT OK\r\n", 1000, 2) != GPRS_SUCCESS) { //关闭连接 发送 AT+CIPSHUT\n 应答 SHUT OK
        printf("NetGprs_SendCmd AT+CIPSHUT err\r\n");
        goto OVER;
    }

    if (NetGprs_SendCmd("AT+CGREG?\n", "+CGREG: 0,1\r\n", 5000, 3) != GPRS_SUCCESS) { //查看当前GPRS注册状态
        printf("NetGprs_SendCmd AT+CGREG? err\r\n");
        goto OVER;
    }

    if (NetGprs_SendCmd("AT+CIPMUX=0\n", "OK\r\n", 5000, 5) != GPRS_SUCCESS) { //设置为单链接模式
        printf("NetGprs_SendCmd AT+CIPMUX=0 err\r\n");
        goto OVER;
    }

    if (NetGprs_SendCmd("AT+CIPQSEND=0\n", "OK\r\n", 5000, 3) != GPRS_SUCCESS) { //设置为慢发模式
        printf("NetGprs_SendCmd AT+CIPQSEND=0 err\r\n");
        goto OVER;
    }

    if (NetGprs_SendCmd("AT+CSTT=\"CMNET\"\n", "OK\r\n", 1000, 2) != GPRS_SUCCESS) { //启动任务 CNMET 发送 AT+CSTT=\"CMNET\"\n   应答OK
        printf("NetGprs_SendCmd AT+CSTT err\r\n");
        goto OVER;
    }

    if (NetGprs_SendCmd("AT+CIICR\n", "OK\r\n", 90000, 1) != GPRS_SUCCESS) { //发送 AT+CIICR\n  应答 OK
        printf("NetGprs_SendCmd AT+CIICR err\r\n");
        goto OVER;
    }

    NetGprs_SendCmd("AT+CIFSR\n", "", 1000, 1);

    if(!NetGprs_SendATCIPSTART(ng)) { //连接到服务器
        printf("NetGprs_SendCmd ATCIPSTART err\r\n");
        goto OVER;
    }

    if (NetGprs_SendCmd("AT+CIPSPRT=0\n", "OK\r\n", 1000, 10) != GPRS_SUCCESS) { //设置发送数据不显示">" 和SEND OK
        printf("NetGprs_SendCmd AT+CIPSPRT=0 err\r\n");
        goto OVER;
    }

    if (NetGprs_SendCmd("AT+CIPHEAD=1\n", "OK\r\n", 1000, 10) != GPRS_SUCCESS) { //设置接收数据时是否显示IP头
        printf("NetGprs_SendCmd AT+CIPHEAD=1 err\r\n");
        goto OVER;
    }

    NetGprs_SetGPRSLink(ng, (int32_t)1);//设置状态为连接
    return 1;

OVER:
    printf("over reset\r\n");
    NetGprs_Reset();

    ng->reLinkCnt++;

    return 0;
}

static void NetGprs_init(struct T_NetGprs *ng) {
    const char *CFUN0 = "AT+CFUN=0\n";
    NetGprs_GprsWrite(CFUN0, strlen(CFUN0));

    os_msleep(5000);//强制等待5秒;

    const char *CFUN1 = "AT+CFUN=1\n";
    NetGprs_GprsWrite(CFUN1, strlen(CFUN0));

    os_msleep(500);//强制等待500毫秒;
    NetGprs_Connect(ng); //说明发起连接成功
}

int32_t NetGprs_IsGrpsConnect(void) {
    return g_gprs.linkstate;
}

int32_t gprs_connect(void) {
    if (g_gprs.linkstate){
        if (NetGprs_CheckGprsLink() == 0) {
            g_gprs.linkstate = 0;
            NetGprs_init(&g_gprs);
        }
    }else{
        NetGprs_init(&g_gprs);
    }
    if (g_gprs.linkstate){
        return 0;
    }
    return -1;
}

int32_t gprs_send_msg(const char *buf, uint32_t buflen) {
    if (buflen >= GPRS_RECV_BUF_LEN_MAX) {
        printf("NetGprs_SendMsg len:%d > max:%d\r\n", (int)buflen, (int)GPRS_RECV_BUF_LEN_MAX);
        return -1;
    }
    if (!g_gprs.linkstate) {
        return -1;
    }
    char bufsend[GPRS_RECV_BUF_LEN_MAX] = {0};
    sprintf(bufsend, "AT+CIPSEND=%d\n", (int)buflen);

    NetGprs_GprsWrite((const char *)bufsend, strlen(bufsend));

    memset(bufsend, 0, sizeof(bufsend));
    memcpy(bufsend, buf, buflen);
    bufsend[buflen] = '\n';

    NetGprs_GprsWrite((const char *)bufsend, buflen + 1);
    os_msleep(50);
    return buflen;
}

int32_t gprs_read_msg(char_t *buf, uint32_t len){
    uint32_t i=0;
    for(i=0;i<len;i++){
        BaseType_t xResult = xQueueReceive(gprs_recv_queue, &buf[i], portTICK_PERIOD_MS);
        if (xResult != pdPASS){
            break;
        }    
    }

    return i;
}

void poll_recv(void){
    uint8_t data;
    if(usart3_receive(&data)){
       //printf("%c",data);
       GprsRecv_Parse(data);
    }
}

void poll_task(void *para){
    while(1){
        poll_recv();
        
        os_msleep(1);
    }
}
int32_t gprs_init(char_t *ip, uint32_t port){
    int32_t ret = 0;

    os_pthread_t gprs_recv_thread;
    
    int32_t addr_val[4]={0};
    sscanf(ip, "%d.%d.%d.%d", &addr_val[0], &addr_val[1], &addr_val[2], &addr_val[3]);
    g_gprs.serveip[0] = addr_val[0];
    g_gprs.serveip[1] = addr_val[1];
    g_gprs.serveip[2] = addr_val[2];
    g_gprs.serveip[3] = addr_val[3];
    g_gprs.serveport = port;
    usart3_init(9600u);
    gprs_port_init();
    gprs_power_on();
    gprs_recv_queue = xQueueCreate(GPRS_RECV_DATA_LEN, sizeof(uint8_t));
    if (os_pthread_create("gprs_poll", &gprs_recv_thread, poll_task, NULL,  OS_TASK_PRIO_HIGHT, OS_STACK_SIZE_LARGE) != 0){
        ret = -1;
    } 
    
    return ret;
}

